package com.jfire.orm.function.impl;

import java.awt.List;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import sun.misc.Unsafe;
import com.jfire.baseutil.StringUtil;
import com.jfire.baseutil.collection.StringCache;
import com.jfire.baseutil.collection.set.LightSet;
import com.jfire.baseutil.reflect.ReflectUtil;
import com.jfire.baseutil.simplelog.ConsoleLogFactory;
import com.jfire.baseutil.simplelog.Logger;
import com.jfire.baseutil.verify.Verify;
import com.jfire.orm.annotation.Id;
import com.jfire.orm.annotation.OrmIgnore;
import com.jfire.orm.annotation.TableEntity;
import com.jfire.orm.field.MapField;
import com.jfire.orm.field.impl.IntegerField;
import com.jfire.orm.field.impl.LongField;
import com.jfire.orm.field.impl.StringField;
import com.jfire.orm.function.DAOBean;
import com.jfire.orm.util.DaoFactory;

@SuppressWarnings("restriction")
public class DAOBeanImpl implements DAOBean
{
    private static Logger logger   = ConsoleLogFactory.getLogger();
    private String        deleteSql;
    private Class<?>      entityClass;
    private String        getSql;
    private String        saveSql;
    private String        updateSql;
    // 代表数据库主键id的field
    private MapField      idField;
    private MapField[]    valueFields;
    private int           valueNum = 0;
    private long          idOffset;
    private Unsafe        unsafe   = ReflectUtil.getUnsafe();
    
    public DAOBeanImpl(Class<?> entityClass)
    {
        this.entityClass = entityClass;
        Field[] fields = ReflectUtil.getAllFields(entityClass);
        LightSet<MapField> set = new LightSet<>();
        for (Field each : fields)
        {
            if (each.isAnnotationPresent(OrmIgnore.class) || Map.class.isAssignableFrom(each.getType()) || List.class.isAssignableFrom(each.getType()) || each.getType().isInterface() || each.getType().isArray() || Modifier.isStatic(each.getModifiers()))
            {
                continue;
            }
            set.add(DaoFactory.buildMapField(each));
            if (each.isAnnotationPresent(Id.class))
            {
                idField = DaoFactory.buildMapField(each);
                idOffset = unsafe.objectFieldOffset(each);
            }
        }
        Verify.notNull(idField, "使用TableEntity映射的表必须由id字段，请检查{}", entityClass.getName());
        valueFields = set.toArray(MapField.class);
        valueNum = valueFields.length;
        buildSql();
    }
    
    private void buildSql()
    {
        TableEntity tableEntity = entityClass.getAnnotation(TableEntity.class);
        String tableName = tableEntity.name();
        StringCache cache = new StringCache();
        /******** 生成insertSql *******/
        cache.append("insert into ").append(tableName).append(" (");
        for (MapField each : valueFields)
        {
            cache.append(each.getColName()).append(',');
        }
        cache.deleteLast().append(") values (");
        cache.appendStrsByComma("?", valueNum);
        cache.append(')');
        saveSql = cache.toString();
        /******** 生成insertSql *******/
        /******** 生成updatesql *******/
        cache.clear();
        cache.append("update ").append(tableName).append(" set ");
        for (MapField each : valueFields)
        {
            cache.append(each.getColName()).append("=?,");
        }
        cache.deleteLast().append(" where ").append(idField.getColName()).append("=?");
        updateSql = cache.toString();
        /******** 生成updatesql *******/
        /******** 生成deletesql *****/
        cache.clear();
        cache.append("delete from ").append(tableName).append("  where ").append(idField.getColName()).append("=?");
        deleteSql = cache.toString();
        /******** 生成deletesql *****/
        /******** 生成getSql ******/
        cache.clear();
        cache.append("select ");
        for (MapField each : valueFields)
        {
            cache.append(each.getColName()).append(",");
        }
        cache.deleteLast().append(" from ").append(tableName).append(" where ").append(idField.getColName()).append("=?");
        getSql = cache.toString();
        /******** 生成getSql ******/
        logger.debug("生成的save语句是:{}", saveSql);
        logger.debug("生成的delete语句是:{}", deleteSql);
        logger.debug("生成的update语句是:{}", updateSql);
        logger.debug("生成的get语句是:{}", getSql);
    }
    
    @Override
    public boolean delete(Object entity, Connection connection)
    {
        try (PreparedStatement pstat = connection.prepareStatement(deleteSql))
        {
            pstat.setObject(1, unsafe.getObject(entity, idOffset));
            pstat.executeUpdate();
            return true;
        }
        catch (SQLException e)
        {
            throw new RuntimeException(e);
        }
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public <T> T getById(Object pk, Connection connection)
    {
        try (PreparedStatement pStat = connection.prepareStatement(getSql))
        {
            pStat.setObject(1, pk);
            ResultSet resultSet = pStat.executeQuery();
            if (resultSet.next())
            {
                Object entity = entityClass.newInstance();
                for (MapField each : valueFields)
                {
                    each.setEntityValue(entity, resultSet);
                }
                return (T) entity;
            }
            else
            {
                return null;
            }
        }
        catch (SQLException | InstantiationException | IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
    }
    
    @Override
    public <T> void save(T entity, Connection connection)
    {
        Object idValue = unsafe.getObject(entity, idOffset);
        if (idValue == null)
        {
            // id值为null，执行插入操作
            insert(entity, connection);
        }
        else
        {
            // id有值，执行更新操作
            try (PreparedStatement pStat = connection.prepareStatement(updateSql))
            {
                for (int i = 0; i < valueNum; i++)
                {
                    valueFields[i].setStatementValue(pStat, entity, i + 1);
                }
                idField.setStatementValue(pStat, entity, valueNum + 1);
                pStat.executeUpdate();
            }
            catch (SQLException e)
            {
                throw new RuntimeException(e);
            }
        }
        
    }
    
    public <T> void insert(T entity, Connection connection)
    {
        try (PreparedStatement pStat = connection.prepareStatement(saveSql, Statement.RETURN_GENERATED_KEYS))
        {
            for (int i = 0; i < valueNum; i++)
            {
                valueFields[i].setStatementValue(pStat, entity, i + 1);
            }
            pStat.executeUpdate();
            ResultSet resultSet = pStat.getGeneratedKeys();
            resultSet.next();
            if (idField instanceof IntegerField)
            {
                unsafe.putObject(entity, idOffset, resultSet.getInt(1));
            }
            else if (idField instanceof StringField)
            {
                unsafe.putObject(entity, idOffset, resultSet.getString(1));
            }
            else if (idField instanceof LongField)
            {
                unsafe.putObject(entity, idOffset, resultSet.getLong(1));
            }
            else
            {
                throw new RuntimeException(StringUtil.format("id字段暂时支持Integer,Long,String.请检查{}", entity.getClass().getName()));
            }
        }
        catch (Exception e)
        {
            logger.error("保存出现异常", e);
            throw new RuntimeException(e);
        }
    }
    
}
